/**
  ******************************************************************************
  * @file    rs485n1.c
  * @brief   This file provides code for the configuration
  *          of all used GPIO pins.
  ******************************************************************************
  * @attention
  *
  ******************************************************************************
  */

/* Includes ------------------------------------------------------------------*/
#include "bsp.h"
#include "tskcfg.h"
#include "rs485n1.h"

static void rs485n1_uart_timeout(void)
{
  LL_TIM_InitTypeDef TIM_InitStruct = {0};
  
  RS485N1_OUTTIMER_EnableClock();

  /* TIM4 interrupt Init */
  NVIC_SetPriority(RS485N1_OUTTIMER_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),RS485N1_OUTTIMER_IRQ_PRIORITY, 0));
  NVIC_EnableIRQ(RS485N1_OUTTIMER_IRQn);

  TIM_InitStruct.Prescaler = 100-1;     /* 1us per cnt */;
  TIM_InitStruct.CounterMode = LL_TIM_COUNTERMODE_UP;
  TIM_InitStruct.Autoreload = 1800-1;   /* 1.8ms */;
  TIM_InitStruct.ClockDivision = LL_TIM_CLOCKDIVISION_DIV1;
  LL_TIM_Init(RS485N1_OUTTIMER, &TIM_InitStruct);
  
  LL_TIM_EnableARRPreload(RS485N1_OUTTIMER);
  
  LL_TIM_SetClockSource(RS485N1_OUTTIMER, LL_TIM_CLOCKSOURCE_INTERNAL);
  
  LL_TIM_SetOnePulseMode(RS485N1_OUTTIMER, LL_TIM_ONEPULSEMODE_SINGLE);//LL_TIM_ONEPULSEMODE_REPETITIVE
  
  LL_TIM_SetTriggerOutput(RS485N1_OUTTIMER, LL_TIM_TRGO_RESET);
  
  LL_TIM_DisableMasterSlaveMode(RS485N1_OUTTIMER);
  
  LL_TIM_ClearFlag_UPDATE(RS485N1_OUTTIMER);
  
  LL_TIM_EnableIT_UPDATE(RS485N1_OUTTIMER);
  
  LL_TIM_ClearFlag_UPDATE(RS485N1_OUTTIMER);
  
  LL_TIM_DisableCounter(RS485N1_OUTTIMER);
}

void rs485n1_uart_init(void)
{
  LL_USART_InitTypeDef USART_InitStruct = {0};
  LL_GPIO_InitTypeDef GPIO_InitStruct = {0};

  /* Peripheral clock enable */
  RS485N1_UART_EnableClock();
  RS485N1_UART_IO_EnableClock();
  
  rs485n1_uart_timeout();
  
  GPIO_InitStruct.Pin = RS485N1_TX_LL_Pin | RS485N1_RX_LL_Pin;
  GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
  GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_VERY_HIGH;
  GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
  GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
  GPIO_InitStruct.Alternate = RS485N1_GPIO_LL_AF;
  LL_GPIO_Init(RS485N1_GPIO_Port, &GPIO_InitStruct);
  
  NVIC_SetPriority(RS485N1_UART_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),RS485N1_UART_IRQ_PRIORITY, 0));
  NVIC_EnableIRQ(RS485N1_UART_IRQn);
  
  USART_InitStruct.BaudRate = RS485N1_UART_BAUDRATE;
  USART_InitStruct.DataWidth = LL_USART_DATAWIDTH_8B;
  USART_InitStruct.StopBits = LL_USART_STOPBITS_1;
  USART_InitStruct.Parity = LL_USART_PARITY_NONE;
  USART_InitStruct.TransferDirection = LL_USART_DIRECTION_TX_RX;
  USART_InitStruct.HardwareFlowControl = LL_USART_HWCONTROL_NONE;
  LL_USART_Init(RS485N1_UART, &USART_InitStruct);
  
  LL_USART_SetOverSampling(RS485N1_UART, LL_USART_OVERSAMPLING_16);
  
  LL_USART_DisableOneBitSamp(RS485N1_UART);
  
  LL_USART_ConfigAsyncMode(RS485N1_UART);
  
  LL_USART_DisableIrda(RS485N1_UART);
  
  LL_USART_DisableSmartcard(RS485N1_UART);
  
  LL_USART_DisableHalfDuplex(RS485N1_UART);
  
  LL_USART_DisableLIN(RS485N1_UART);
  
  LL_USART_SetWakeUpMethod(RS485N1_UART, LL_USART_WAKEUP_IDLELINE);

  LL_USART_Enable(RS485N1_UART);
  
  LL_USART_EnableIT_RXNE(RS485N1_UART);
  LL_USART_EnableIT_ERROR(RS485N1_UART);
}

void rs485n1_send_str(const char *buf)
{
  uint32_t i;
  
  for(i=0; buf[i]!='\0'; i++)
  {
    RS485N1_UART->DR = (buf[i] & (uint16_t)0x01FFU);
    while(READ_BIT(RS485N1_UART->SR, USART_SR_TXE) != (USART_SR_TXE));
  }
  
  while(READ_BIT(RS485N1_UART->SR, USART_SR_TC) != (USART_SR_TC));
}

void rs485n1_send_buf(const uint8_t *buf, uint32_t len)
{
  uint32_t i;
  
  for(i=0; i<len; i++)
  {
    RS485N1_UART->DR = (buf[i]& (uint16_t)0x01FFU);
    while(READ_BIT(RS485N1_UART->SR, USART_SR_TXE) != (USART_SR_TXE));
  }
  
  while(READ_BIT(RS485N1_UART->SR, USART_SR_TC) != (USART_SR_TC));
}

void RS485N1_UART_IRQHandler(void)
{
  if((READ_BIT(RS485N1_UART->SR, USART_SR_RXNE) == (USART_SR_RXNE)) && \
     (READ_BIT(RS485N1_UART->CR1, USART_CR1_RXNEIE) == (USART_CR1_RXNEIE)))
  {
    CLEAR_BIT(RS485N1_OUTTIMER->CR1, TIM_CR1_CEN);
    
//    ssp_protc_rcvisr((__I uint8_t)(READ_BIT(RS485N1_UART->DR, USART_DR_DR)));
    
    WRITE_REG(RS485N1_OUTTIMER->CNT, 0);
    SET_BIT(RS485N1_OUTTIMER->CR1, TIM_CR1_CEN);
  }
}

void RS485N1_OUTTIMER_IRQHandler(void)
{
  if(LL_TIM_IsActiveFlag_UPDATE(RS485N1_OUTTIMER) == 1)
  {
    LL_TIM_ClearFlag_UPDATE(RS485N1_OUTTIMER);

//    ssp_protc_rcvtimeout();
  }
}
